/*
 * Copyright (c) Huawei Technologies Co., Ltd. 2023-2023. All rights reserved.
 *
 */

import { CompileModeEnum } from '../../../src/enum/compile-mode-enum.js';
import { BuildOptionWithName } from '../../../src/options/build/build-opt.js';
import { BuildOptionCombiner as combiner } from '../../../src/project/build-option/build-option-util.js';
import { BuildOptionUtil } from '../../../src/project/build-option/build-option-util.js';

test('combineBuildOption function', () => {
  const option1 = {
    name: 'debug',
    packageOptions: {
      mainPackageLimitSize: 23,
      normalPackageLimitSize: 100
    },
    resOptions: {
      resName: 'aaa',
      obj1: {
        name: 'obj1Name'
      }
    },
    artifactType: 'bbb',
    sourceOption: {
      workers: ['worker1', 'worker2', 'worker3']
    }
  };
  const option2 = {
    name: 'debug',
    packageOptions: {
      mainPackageLimitSize: 22,
    },
    resOptions: {
      resName: 'bbb',
      obj1: {
        name: 'obj1Name2',
        age: 30
      }
    },
    artifactType: 'ccc',
    sourceOption: {
      workers: ['worker1', 'worker2']
    },
    compileMode: CompileModeEnum.JS_BUNDLE,
    apPath: 'app'
  };
  const option3 = {
    name: 'release',
    packageOptions: {
      normalPackageLimitSize: 200,
    },
    externalNativeOptions: {
      path: 'path'
    },
    compileMode: CompileModeEnum.ES_MODULE
  };

  const replace12 = combiner.replaceBuildOption(option1, option2);
  expect(replace12).toEqual({
    name: 'debug',
    packageOptions: {
      mainPackageLimitSize: 22,
    },
    resOptions: {
      resName: 'bbb',
      obj1: {
        name: 'obj1Name2',
        age: 30
      }
    },
    artifactType: 'ccc',
    sourceOption: {
      workers: ['worker1', 'worker2']
    },
    compileMode: CompileModeEnum.JS_BUNDLE,
    apPath: 'app'
  });

  expect(() => combiner.replaceBuildOption(option1, option3)).toThrowError();
  const merge12 = combiner.mergeBuildOption(option1, option2);
  expect(merge12).toEqual({
    name: 'debug',
    packageOptions: {mainPackageLimitSize: 22, normalPackageLimitSize: 100},
    resOptions: {resName: 'bbb', obj1: {name: 'obj1Name2', age: 30}},
    artifactType: 'ccc',
    sourceOption: {workers: ['worker1', 'worker2']},
    compileMode: 'jsbundle',
    apPath: 'app'
  });

  const merge13 = combiner.mergeBuildOption(option1, option3);
  expect(merge13).toEqual({
    name: 'release',
    packageOptions: {mainPackageLimitSize: 23, normalPackageLimitSize: 200},
    resOptions: {resName: 'aaa', obj1: {name: 'obj1Name'}},
    artifactType: 'bbb',
    sourceOption: {workers: ['worker1', 'worker2', 'worker3']},
    externalNativeOptions: {path: 'path'},
    compileMode: 'esmodule'
  });

  const merge23 = combiner.mergeBuildOption(option2, option3);
  expect(merge23).toEqual({
    name: 'release',
    packageOptions: {mainPackageLimitSize: 22, normalPackageLimitSize: 200},
    resOptions: {resName: 'bbb', obj1: {name: 'obj1Name2', age: 30}},
    artifactType: 'ccc',
    sourceOption: {workers: ['worker1', 'worker2']},
    compileMode: 'esmodule',
    apPath: 'app',
    externalNativeOptions: {path: 'path'}
  });
});

test('buildOption copyFrom function', () => {
  let buildOptionMap: Map<string, BuildOptionWithName>;

  // 测试无 copyFrom 的情况
  const buildOptionSet1: BuildOptionWithName[] = [
    {
      name: 'debug',
      apPath: 'appPathDebug',
      sourceOption: {
        workers: ['worker1']
      },
    },
  ];
  combiner.processCopyFrom(buildOptionSet1);
  expect(buildOptionSet1[0]).toEqual({
    name: 'debug',
    apPath: 'appPathDebug',
    sourceOption: {
      workers: ['worker1']
    },
  });

  // 测试存在无效的 copyFrom 名字的情况
  const buildOptionSet2: BuildOptionWithName[] = [
    {
      name: 'debug',
      apPath: 'appPathDebug',
      sourceOption: {
        workers: ['worker1']
      },
      copyFrom: 'xxx'
    },
  ];
  buildOptionMap = BuildOptionUtil.buildOptionSetToMap(buildOptionSet2);
  expect(BuildOptionUtil.isCopyFromNameExists(buildOptionSet2[0], buildOptionMap)).toEqual(false);
  combiner.processCopyFrom(buildOptionSet2);
  expect(buildOptionSet2[0]).toEqual({
    name: 'debug',
    apPath: 'appPathDebug',
    sourceOption: {
      workers: ['worker1']
    },
    copyFrom: 'xxx'
  });

  // 测试自己 copyFrom 自己成环的情况
  const buildOptionSet3: BuildOptionWithName[] = [
    {
      name: 'debug',
      apPath: 'appPathDebug',
      sourceOption: {
        workers: ['worker1']
      },
      copyFrom: 'debug'
    },
  ];
  buildOptionMap = BuildOptionUtil.buildOptionSetToMap(buildOptionSet3);
  expect(BuildOptionUtil.isCopyFromHasCircle(buildOptionSet3[0], buildOptionMap)).toEqual(true);

  // 测试正常情况下  A -> B -> C 继承情况
  const buildOptionSet4: BuildOptionWithName[] = [
    {
      name: 'debug',
      apPath: 'appPathDebug',
      sourceOption: {
        workers: ['worker1']
      },
    },
    {
      name: 'release',
      apPath: 'appPathRelease',
      copyFrom: 'debug'
    },
    {
      name: 'release1',
      apPath: 'appPathRelease1',
      sourceOption: {
        workers: ['worker1', 'worker2']
      },
      copyFrom: 'release'
    },
  ];
  buildOptionMap = BuildOptionUtil.buildOptionSetToMap(buildOptionSet4);
  combiner.processCopyFrom(buildOptionSet4);
  expect(BuildOptionUtil.isCopyFromHasCircle(buildOptionSet4[2], buildOptionMap)).toEqual(false);
  expect(buildOptionSet4[1]).toEqual({
    name: 'release',
    apPath: 'appPathRelease',
    sourceOption: {workers: ['worker1']},
    copyFrom: 'debug'
  });
  expect(buildOptionSet4[2]).toEqual({
    name: 'release1',
    apPath: 'appPathRelease1',
    sourceOption: {workers: ['worker1', 'worker2']},
    copyFrom: 'release'
  });

  // 测试继承链中有无效name的情况
  const buildOptionSet5: BuildOptionWithName[] = [
    {
      name: 'debug',
      apPath: 'appPathDebug',
      sourceOption: {
        workers: ['worker1']
      },
      copyFrom: 'xxx'
    },
    {
      name: 'release',
      apPath: 'appPathRelease',
      debuggable: true,
      copyFrom: 'debug'
    },
    {
      name: 'release1',
      apPath: 'appPathRelease1',
      copyFrom: 'release'
    },
  ];
  combiner.processCopyFrom(buildOptionSet5);
  expect(buildOptionSet5[1]).toEqual({
    name: 'release',
    apPath: 'appPathRelease',
    sourceOption: {workers: ['worker1']},
    copyFrom: 'debug',
    debuggable: true
  });
  expect(buildOptionSet5[2]).toEqual({
    name: 'release1',
    apPath: 'appPathRelease1',
    sourceOption: {workers: ['worker1']},
    copyFrom: 'release',
    debuggable: true
  });

  // 测试circle成环检查
  const buildOptionSet6: BuildOptionWithName[] = [
    {
      name: 'debug',
      apPath: 'appPathDebug',
      sourceOption: {
        workers: ['worker1']
      },
      copyFrom: 'release1'
    },
    {
      name: 'release',
      apPath: 'appPathRelease',
      copyFrom: 'debug'
    },
    {
      name: 'release1',
      apPath: 'appPathRelease1',
      copyFrom: 'release'
    },
  ];
  buildOptionMap = BuildOptionUtil.buildOptionSetToMap(buildOptionSet6);
  const pathArray6_0: string[] = [];
  const pathArray6_1: string[] = [];
  const pathArray6_2: string[] = [];
  expect(BuildOptionUtil.isCopyFromHasCircle(buildOptionSet6[0], buildOptionMap, pathArray6_0)).toEqual(true);
  expect(BuildOptionUtil.isCopyFromHasCircle(buildOptionSet6[1], buildOptionMap, pathArray6_1)).toEqual(true);
  expect(BuildOptionUtil.isCopyFromHasCircle(buildOptionSet6[2], buildOptionMap, pathArray6_2)).toEqual(true);
  expect(pathArray6_0.join(' -> ')).toEqual('debug -> release1 -> release -> debug');
  expect(pathArray6_1.join(' -> ')).toEqual('release -> debug -> release1 -> release');
  expect(pathArray6_2.join(' -> ')).toEqual('release1 -> release -> debug -> release1');

  // 测试circle成环检查
  const buildOptionSet7: BuildOptionWithName[] = [
    {
      name: 'debug',
      apPath: 'appPathDebug',
      sourceOption: {
        workers: ['worker1']
      },
      copyFrom: 'release'
    },
    {
      name: 'release',
      apPath: 'appPathRelease',
      copyFrom: 'release1'
    },
    {
      name: 'release1',
      apPath: 'appPathRelease1',
      copyFrom: 'release2'
    },
    {
      name: 'release2',
      apPath: 'appPathRelease2',
      copyFrom: 'release'
    },
  ];
  buildOptionMap = BuildOptionUtil.buildOptionSetToMap(buildOptionSet7);
  const pathArray7: string[] = [];
  expect(BuildOptionUtil.isCopyFromHasCircle(buildOptionSet7[0], buildOptionMap, pathArray7)).toEqual(true);
  expect(pathArray7.join(' -> ')).toEqual('debug -> release -> release1 -> release2 -> release');

  const buildOptionSet8: BuildOptionWithName[] = [
    {
      name: 'release',
      apPath: 'appPathRelease',
      copyFrom: 'xxx',
      compileMode: CompileModeEnum.JS_BUNDLE
    },
    {
      name: 'release1',
      apPath: 'appPathRelease1',
      copyFrom: 'release',
      compileMode: CompileModeEnum.ES_MODULE
    },
    {
      name: 'release2',
      apPath: 'appPathRelease2',
      copyFrom: 'release1'
    },
  ];
  combiner.processCopyFrom(buildOptionSet8);
  expect(buildOptionSet8[2]).toEqual({
    name: 'release2',
    apPath: 'appPathRelease2',
    copyFrom: 'release1',
    compileMode: 'esmodule'
  });
});
